using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using WpfClient.Core.Communication;
using WpfClient.Core.Models;

namespace WpfClient.Infrastructure.Communication
{
    /// <summary>
    /// Socket服务器实现
    /// </summary>
    public class SocketServer : ISocketServer, IDisposable
    {
        private readonly ILogger<SocketServer> _logger;
        private TcpListener? _tcpListener;
        private CancellationTokenSource? _cancellationTokenSource;
        private readonly ConcurrentDictionary<string, ConnectedClient> _clients = new();
        private bool _disposed;

        public bool IsRunning { get; private set; }
        public int ConnectedClientsCount => _clients.Count;

        public event EventHandler<ClientConnectedEventArgs>? ClientConnected;
        public event EventHandler<ClientDisconnectedEventArgs>? ClientDisconnected;
        public event EventHandler<DataSentEventArgs>? DataSent;
        public event EventHandler<DataReceivedEventArgs>? DataReceived;

        public SocketServer(ILogger<SocketServer> logger)
        {
            _logger = logger;
        }

        public async Task StartAsync(int port, CancellationToken cancellationToken = default)
        {
            if (IsRunning)
            {
                _logger.LogWarning("Socket服务器已经在运行中");
                return;
            }

            try
            {
                _logger.LogInformation("正在启动Socket服务器，端口: {Port}", port);

                _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                _tcpListener = new TcpListener(IPAddress.Any, port);
                _tcpListener.Start();

                IsRunning = true;
                _logger.LogInformation("Socket服务器启动成功，监听端口: {Port}", port);

                // 开始接受客户端连接
                _ = Task.Run(async () => await AcceptClientsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "启动Socket服务器失败");
                IsRunning = false;
                throw;
            }
        }

        public async Task StopAsync()
        {
            if (!IsRunning)
            {
                _logger.LogWarning("Socket服务器未运行");
                return;
            }

            try
            {
                _logger.LogInformation("正在停止Socket服务器...");

                IsRunning = false;
                _cancellationTokenSource?.Cancel();

                // 断开所有客户端连接
                var disconnectTasks = _clients.Values.Select(client => DisconnectClientAsync(client, "服务器关闭"));
                await Task.WhenAll(disconnectTasks);

                _tcpListener?.Stop();
                _cancellationTokenSource?.Dispose();

                _logger.LogInformation("Socket服务器已停止");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "停止Socket服务器时发生错误");
            }
        }

        public async Task<bool> SendDataAsync(string clientId, byte[] data, byte[] expectedResponseHeader, TimeSpan timeout = default)
        {
            if (!_clients.TryGetValue(clientId, out var client))
            {
                _logger.LogWarning("客户端不存在: {ClientId}", clientId);
                return false;
            }

            if (timeout == default)
                timeout = TimeSpan.FromSeconds(10);

            try
            {
                _logger.LogDebug("向客户端 {ClientId} 发送数据: {Data}", clientId, Convert.ToHexString(data));

                // 发送数据
                await client.NetworkStream.WriteAsync(data);
                await client.NetworkStream.FlushAsync();

                client.ClientInfo.BytesSent += data.Length;
                client.ClientInfo.LastActivity = DateTime.UtcNow;

                // 等待回复
                var response = await WaitForResponseAsync(client, expectedResponseHeader, timeout);
                var success = response != null;

                DataSent?.Invoke(this, new DataSentEventArgs(clientId, data, success, success ? null : "未收到期望的回复"));

                if (success)
                {
                    _logger.LogDebug("客户端 {ClientId} 回复: {Response}", clientId, Convert.ToHexString(response!));
                    DataReceived?.Invoke(this, new DataReceivedEventArgs(clientId, response!));
                }
                else
                {
                    _logger.LogWarning("客户端 {ClientId} 未在超时时间内回复期望的数据", clientId);
                }

                return success;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "向客户端 {ClientId} 发送数据失败", clientId);
                DataSent?.Invoke(this, new DataSentEventArgs(clientId, data, false, ex.Message));
                return false;
            }
        }

        public async Task<Dictionary<string, bool>> SendDataToAllAsync(byte[] data, byte[] expectedResponseHeader, TimeSpan timeout = default)
        {
            var results = new Dictionary<string, bool>();
            var tasks = new List<Task>();

            foreach (var clientId in _clients.Keys.ToList())
            {
                tasks.Add(Task.Run(async () =>
                {
                    var success = await SendDataAsync(clientId, data, expectedResponseHeader, timeout);
                    lock (results)
                    {
                        results[clientId] = success;
                    }
                }));
            }

            await Task.WhenAll(tasks);
            return results;
        }

        public async Task<IEnumerable<ClientInfo>> GetConnectedClientsAsync()
        {
            return await Task.FromResult(_clients.Values.Select(c => c.ClientInfo).ToList());
        }

        private async Task AcceptClientsAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested && IsRunning)
            {
                try
                {
                    var tcpClient = await _tcpListener!.AcceptTcpClientAsync();
                    var clientEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint;
                    var clientId = Guid.NewGuid().ToString();

                    var clientInfo = new ClientInfo
                    {
                        Id = clientId,
                        IpAddress = clientEndPoint?.Address.ToString() ?? "Unknown",
                        Port = clientEndPoint?.Port ?? 0,
                        ConnectedAt = DateTime.UtcNow,
                        IsConnected = true,
                        LastActivity = DateTime.UtcNow
                    };

                    var connectedClient = new ConnectedClient
                    {
                        Id = clientId,
                        TcpClient = tcpClient,
                        NetworkStream = tcpClient.GetStream(),
                        ClientInfo = clientInfo,
                        ResponseWaitHandle = new SemaphoreSlim(0, 1),
                        PendingResponse = null
                    };

                    _clients[clientId] = connectedClient;

                    _logger.LogInformation("客户端连接: {ClientId} ({IpAddress}:{Port})", 
                        clientId, clientInfo.IpAddress, clientInfo.Port);

                    ClientConnected?.Invoke(this, new ClientConnectedEventArgs(clientInfo));

                    // 开始处理客户端数据
                    _ = Task.Run(async () => await HandleClientAsync(connectedClient, cancellationToken), cancellationToken);
                }
                catch (ObjectDisposedException)
                {
                    // 服务器正在关闭
                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "接受客户端连接时发生错误");
                }
            }
        }

        private async Task HandleClientAsync(ConnectedClient client, CancellationToken cancellationToken)
        {
            var buffer = new byte[4096];

            try
            {
                while (!cancellationToken.IsCancellationRequested && client.TcpClient.Connected)
                {
                    var bytesRead = await client.NetworkStream.ReadAsync(buffer, cancellationToken);
                    if (bytesRead == 0)
                    {
                        // 客户端断开连接
                        break;
                    }

                    var receivedData = new byte[bytesRead];
                    Array.Copy(buffer, receivedData, bytesRead);

                    client.ClientInfo.BytesReceived += bytesRead;
                    client.ClientInfo.LastActivity = DateTime.UtcNow;

                    _logger.LogDebug("从客户端 {ClientId} 接收到数据: {Data}", 
                        client.Id, Convert.ToHexString(receivedData));

                    // 检查是否是等待的回复
                    if (client.PendingResponse != null)
                    {
                        if (IsExpectedResponse(receivedData, client.PendingResponse))
                        {
                            client.ReceivedResponse = receivedData;
                            client.ResponseWaitHandle.Release();
                        }
                    }

                    DataReceived?.Invoke(this, new DataReceivedEventArgs(client.Id, receivedData));
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理客户端 {ClientId} 数据时发生错误", client.Id);
            }
            finally
            {
                await DisconnectClientAsync(client, "连接断开");
            }
        }

        private async Task<byte[]?> WaitForResponseAsync(ConnectedClient client, byte[] expectedHeader, TimeSpan timeout)
        {
            client.PendingResponse = expectedHeader;
            client.ReceivedResponse = null;

            try
            {
                var success = await client.ResponseWaitHandle.WaitAsync(timeout);
                return success ? client.ReceivedResponse : null;
            }
            finally
            {
                client.PendingResponse = null;
                client.ReceivedResponse = null;
            }
        }

        private static bool IsExpectedResponse(byte[] receivedData, byte[] expectedHeader)
        {
            if (receivedData.Length < expectedHeader.Length)
                return false;

            for (int i = 0; i < expectedHeader.Length; i++)
            {
                if (receivedData[i] != expectedHeader[i])
                    return false;
            }

            return true;
        }

        private async Task DisconnectClientAsync(ConnectedClient client, string reason)
        {
            try
            {
                if (_clients.TryRemove(client.Id, out _))
                {
                    client.ClientInfo.IsConnected = false;
                    
                    _logger.LogInformation("客户端断开连接: {ClientId} - {Reason}", client.Id, reason);
                    
                    ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(client.ClientInfo, reason));
                    
                    client.NetworkStream?.Close();
                    client.TcpClient?.Close();
                    client.ResponseWaitHandle?.Dispose();
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "断开客户端 {ClientId} 连接时发生错误", client.Id);
            }

            await Task.CompletedTask;
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                StopAsync().Wait();
                _disposed = true;
            }
        }

        private class ConnectedClient
        {
            public string Id { get; set; } = string.Empty;
            public TcpClient TcpClient { get; set; } = null!;
            public NetworkStream NetworkStream { get; set; } = null!;
            public ClientInfo ClientInfo { get; set; } = null!;
            public SemaphoreSlim ResponseWaitHandle { get; set; } = null!;
            public byte[]? PendingResponse { get; set; }
            public byte[]? ReceivedResponse { get; set; }
        }
    }
}